/*
* Copyright (c) 2025 Shenzhen Kaihong Digital Industry Development Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const { XTools } = require("../../XTools");
const { XMat4 } = require("../XMat4");
const { XNodeFast } = require("../XNodeFast");
const { XTexture } = require("../XTexture");
const { X2DBeta } = require("./X2DBeta");

class XAnimaFast {
    constructor(nf) {
        this.nodeFast_ = nf;
        this.node_ = nf.data_;

        this.animas = {};
        this.animasIndexByName_ = {};
        this.animasIndexByPath_ = {};
        this.bInited = false;
    }
    // {
    //     anima:[{
    //         ele:[image_node_id,cut_id]
    //         acts:[
    //             [frame,x,y,sw,sh,ra,alpha],
    //             [frame,x,y,sw,sh,ra,alpha],
    //         ]}
    //     ]
    // }

    GenAnima(node) {
        let frames = {};
        let rids = [];
        for (let ani of node.anima) {
            let img = this.nodeFast_.GetNodeById(ani.ele[0]);
            let cut = img.cut[ani.ele[1]];//x,y,w,h,ox,oy
            let cutid = XTexture.MakeCut(img.rid, cut[0], cut[1], cut[2], cut[3]);
            rids.push(img.rid);
            if (node.loop) {//fcount
                if (ani.acts.length > 0) {
                    for (let fp = 0; fp < node.fcount; fp++) {
                        if (!(fp in frames)) {
                            frames[fp] = [];
                        }

                        let a1 = null, a2;
                        if (ani.acts.length == 1) {
                            a1 = ani.acts[0];
                            a2 = ani.acts[0];
                        }
                        else if (fp < ani.acts[0][0] || fp > ani.acts[ani.acts.length - 1][0]) {
                            a1 = ani.acts[ani.acts.length - 1];
                            a2 = ani.acts[0];
                        }
                        else {
                            for (let i = 0; i < ani.acts.length - 1; i++) {
                                if (ani.acts[i][0] <= fp && fp <= ani.acts[i + 1][0]) {
                                    a1 = ani.acts[i];
                                    a2 = ani.acts[i + 1];
                                }
                            }
                        }
                        if (!a1) {
                            continue;
                        }
                        // let rate = (a1[0] - fp) / (a2[0] - fp);
                        // if (a2[0] == fp) {
                        //     rate = 0;
                        // }
                        let rate = (fp - a1[0]) / (a2[0] - a1[0]);
                        if (a2[0] == a1[0]) {
                            rate = 0;
                        }
                        frames[fp].push({
                            cid: cutid,
                            mat: XMat4.MakeMat(null,
                                a1[1] + (a2[1] - a1[1]) * rate,
                                a1[2] + (a2[2] - a1[2]) * rate,
                                a1[3] + (a2[3] - a1[3]) * rate,
                                a1[4] + (a2[4] - a1[4]) * rate,
                                a1[5] + (a2[5] - a1[5]) * rate,
                                cut[4], cut[5]),
                            // alpha: (parseInt((f1[6] + (f2[6] - f1[6]) * rate) * 255) << 24),
                            alpha: a1[6] + (a2[6] - a1[6]) * rate,
                        });
                    }
                }
            }
            else {
                for (let i = 0; i < ani.acts.length; i++) {
                    let f1 = ani.acts[i];
                    if (i + 1 < ani.acts.length) {
                        let f2 = ani.acts[i + 1];
                        for (let fp = f1[0]; fp < f2[0]; fp++) {
                            if (!(fp in frames)) {
                                frames[fp] = [];
                            }
                            let rate = (f1[0] - fp) / (f2[0] - fp);
                            frames[fp].push({
                                cid: cutid,
                                mat: XMat4.MakeMat(null,
                                    f1[1] + (f2[1] - f1[1]) * rate,
                                    f1[2] + (f2[2] - f1[2]) * rate,
                                    f1[3] + (f2[3] - f1[3]) * rate,
                                    f1[4] + (f2[4] - f1[4]) * rate,
                                    f1[5] + (f2[5] - f1[5]) * rate,
                                    cut[4], cut[5]),
                                // alpha: (parseInt((f1[6] + (f2[6] - f1[6]) * rate) * 255) << 24),
                                alpha: f1[6] + (f2[6] - f1[6]) * rate,
                            });
                        }
                    }
                    else {
                        let fp = f1[0];
                        if (!(fp in frames)) {
                            frames[fp] = [];
                        }
                        frames[fp].push({
                            cid: cutid,
                            mat: XMat4.MakeMat(null, f1[1], f1[2], f1[3], f1[4], f1[5], cut[4], cut[5]),
                            // alpha: (parseInt((f1[6] + (f2[6] - f1[6]) * rate) * 255) << 24),
                            alpha: f1[6],
                        });
                    }
                }
            }
        }
        this.animas[node.id] = {
            id: node.id,
            node: node,
            name: node.name,
            path: XNodeFast.GetPath(node),
            frames: frames,
            rids: rids,
            count: node.fcount,
        }
        this.animasIndexByName_[this.animas[node.id].name] = this.animas[node.id];
        this.animasIndexByPath_[this.animas[node.id].path] = this.animas[node.id];
    }

    GenerateAnimaData_(node) {
        if (node.type == "ani") {
            this.GenAnima(node);
        }
        else if (node.type == "branch") {
            for (let n of node.child) {
                this.GenerateAnimaData_(n);
            }
        }
    }
    Loaded(node, collect) {
        if (node.type == "ani") {
            for (let ani of node.anima) {
                let n = this.nodeFast_.GetNodeById(ani.ele[0]);
                collect.total++;
                if (n.rid == -1) {
                    let url = XNodeFast.GetUrl(this.node_) + "res/png/" + n.id + ".png";
                    n.rid = XTexture.LoadTextureFromImage(url);
                }
                else {
                    let img = XTexture.GetImage(n.rid);
                    if (img.stat > 0) {
                        collect.loaded++;
                    }
                }
            }
        }
        else if (node.type == "branch") {
            for (let n of node.child) {
                this.Loaded(n, collect);
            }
        }
    }
    IsImageLoaded() {
        let collect = {
            total: 0,
            loaded: 0,
        }
        this.Loaded(this.node_, collect);
        if (!this.bInited && collect.loaded == collect.total) {
            this.GenerateAnimaData_(this.node_);
            this.bInited = true;
        }
        return collect.loaded == collect.total;
    }
    CommitAnimaData() { }
    LocateAnima(name) {
        if (name in this.animas) {//name is id
            return name;
        }
        if (name in this.animasIndexByName_) {
            return this.animasIndexByName_[name].id;
        }
        if (name in this.animasIndexByPath_) {
            return this.animasIndexByPath_[name].id;
        }
        return -1;
    }

    // static drawCutStatic(node, cid, mat, c) {
    //     let b = node.cut[cid];
    //     let tmat = XMat4.MakeMat(null, 0, 0, 1, 1, 0, b[4], b[5]);
    //     tmat.Mult(mat);

    //     if (node.rid < 0) {
    //         if (node.rid == -1) {
    //             WsClient2.SendPackage("downloadimage1", {
    //                 id: node.id
    //             });
    //             node.rid = -2;
    //         }
    //         return;
    //     }
    //     let tc = XTexture.TmpCut(node.rid, b[0], b[1], b[2], b[3]);
    //     if (tc < 0) {
    //         return;
    //     }
    //     // let c = (parseInt(alpha * 255) << 24) | 0xffffff;
    //     X2DBeta.drawCutEx(tc, tmat.mat, c);
    // }
    // static DrawAnimaStatic(node, mat, c = 0xffffffff, frame = -1) {
    //     if (frame == -1) {
    //         frame = XTools.FRAME_AUTOINCRASE % node.fcount;
    //     }
    //     else {
    //         frame = frame % node.fcount;
    //     }

    //     let tmat = new XMat4();
    //     for (let j = 0; j < node.anima.length; j++) {
    //         let acts = node.anima[j].acts;
    //         let n = GNode.GetNodeById(node.anima[j].ele[0]);
    //         let cid = node.anima[j].ele[1];
    //         let p1 = 0;
    //         let frame1 = acts[p1][0];
    //         let p2 = p1 + 1;
    //         if (p2 >= acts.length) {
    //             p2 = 0;
    //         }
    //         let frame2 = acts[p2][0];
    //         let tframe = frame;
    //         if (!node.loop && tframe < frame1) {
    //             continue;
    //         }
    //         while (true) {
    //             if (frame1 <= tframe && tframe <= frame2) {
    //                 break;
    //             }
    //             p1 = p2;
    //             frame1 = frame2;
    //             p2 += 1;
    //             if (p2 >= acts.length) {
    //                 p2 = 0;
    //                 frame2 = acts[p2][0];
    //                 break;
    //             }
    //             frame2 = acts[p2][0];
    //         }
    //         if (!node.loop && tframe > frame2) {
    //             continue;
    //         }
    //         if (tframe < frame1) tframe += node.fcount;//循环到前面去了
    //         if (frame2 < frame1) frame2 += node.fcount;//循环到前面去了

    //         let rate = 1;
    //         if (frame1 != frame2) {
    //             rate = (frame - frame1) / (frame2 - frame1);
    //         }
    //         let act1 = acts[p1];
    //         let act2 = acts[p2];

    //         XMat4.MakeMat(tmat,
    //             (act2[1] - act1[1]) * rate + act1[1],
    //             (act2[2] - act1[2]) * rate + act1[2],
    //             (act2[3] - act1[3]) * rate + act1[3],
    //             (act2[4] - act1[4]) * rate + act1[4],
    //             (act2[5] - act1[5]) * rate + act1[5]);
    //         tmat.Mult(mat);
    //         let a = parseInt((c >>> 24) * ((act2[6] - act1[6]) * rate + act1[6]));
    //         GAnimaEditor.drawCutStatic(n, cid, tmat, (a << 24) | (c & 0xffffff));
    //     }
    // }
    static TMP_MAT = new XMat4();
    DrawAnima(name, x, y, sw = 1, sh = 1, ra = 0, c = 0xffffffff, fp = -1) {
        let aid = this.LocateAnima(name);
        if (aid < 0) {
            return;
        }
        if (fp == -1) {
            fp = XTools.FRAME_AUTOINCRASE;
        }
        fp = fp % this.animas[aid].count;
        if (fp in this.animas[aid].frames) {
            for (let frame of this.animas[aid].frames[fp]) {
                // let m2 = (new XMat4).Copy(frame.mat);
                XMat4.MakeMat(XAnimaFast.TMP_MAT, x, y, sw, sh, ra, 0, 0);
                XAnimaFast.TMP_MAT.MultRight(frame.mat);
                
                X2DBeta.drawCutEx(frame.cid, XAnimaFast.TMP_MAT.mat, (parseInt((c>>>24)*frame.alpha)<<24)|(c&0xffffff));
                // X2DBeta.drawCut(frame.cid,x,y,sw,sh,ra,0,0,0xffffffff);
            }
        }
    }
}

module.exports = {
    XAnimaFast
}